package com.example.minefieldkeepercloud.util.netty;

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.example.minefieldkeepercloud.network.TcpNetHelper;
import com.example.minefieldkeepercloud.util.SPUtilHelper;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;



/**
 * Created by Administrator on 2018/3/20.
 */

public class NettyClient implements INettyClient {
    private final String TAG = NettyClient.class.getSimpleName();
    private static NettyClient mInstance;
    private Bootstrap bootstrap;
    private Channel channel;
    private String host;
    private int port;
    private HandlerThread workThread = null;
    private Handler mWorkHandler = null;
    private NettyClientHandler nettyClientHandler;
    private final String ACTION_SEND_TYPE = "action_send_type";
    private final String ACTION_SEND_MSG = "action_send_msg";
    private final int MESSAGE_INIT = 0x1;
    private final int MESSAGE_CONNECT = 0x2;
    private final int MESSAGE_SEND = 0x3;
    private final int LOGIN_SEND = 0x4;
    private static final int maxFrameLength = Integer.MAX_VALUE;
    private static final int lengthFieldOffset = 0;
    private static final int lengthFieldLength = 0;
    private static final int lengthAdjustment = 0;
    private static final int initialBytesToStrip = 0;

    private boolean isFirst=false;//是否是第一次连接
    private Handler.Callback mWorkHandlerCallback = new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
//                初始化信息
                case MESSAGE_INIT: {
                    NioEventLoopGroup group = new NioEventLoopGroup();
                    bootstrap = new Bootstrap();
                    bootstrap.channel(NioSocketChannel.class);
                    bootstrap.group(group);
                    bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535));
                    bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new NewEncoder());
                            pipeline.addLast(new NewDecoder(maxFrameLength,lengthFieldOffset,lengthFieldLength,lengthAdjustment,initialBytesToStrip,true));
                            pipeline.addLast(nettyClientHandler);
                        }
                    });
                    break;
                }
//                tcp连接
                case MESSAGE_CONNECT: {
                    try {
                        if (TextUtils.isEmpty(host) || port == 0) {
                            Exception exception = new Exception("Netty host | port is invalid");
                            throw exception;
                        }
                        doConnect();
                    } catch (Exception e) {
                        Log.e(TAG, "connect failed  " + e.getMessage() + "  reconnect delay: ");
                        Log.e(TAG, "服务器连接失败，抛异常");
                        e.printStackTrace();
                        //程序崩溃 重新赋值连接
                        sendReconnectMessage();
                    }


                    break;
                }
//                发送连接
                case MESSAGE_SEND: {
                    final String sendMsg = msg.getData().getString(ACTION_SEND_MSG);
                    final int mt = msg.getData().getInt(ACTION_SEND_TYPE);
                    boolean isSend = false;
                    try {
                        if (channel != null && channel.isOpen()) {


                            com.example.minefieldkeepercloud.util.netty.Message sss = new com.example.minefieldkeepercloud.util.netty.Message((byte)mt,  sendMsg);
                            ChannelFuture channelFuture = channel.writeAndFlush(sss);
                            channelFuture.sync();
                            channelFuture.addListener(new ChannelFutureListener() {
                                @Override
                                public void operationComplete(ChannelFuture channelFuture) {

                                    nettyClientHandler.callListeners(TcpNetHelper.SENDSUCC,mt+"");
                                    Log.d(TAG, "send succeed " + mt + sendMsg);


                                }
                            });
                            isSend = true;

                        } else {
                            throw new Exception("channel is null | closed  ");
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "send failed " + e.getMessage());
                        sendReconnectMessage();
                        e.printStackTrace();
                    } finally {
//                        if (Constant.MT.HAND_SHAKE.getType() == mt)
                        //两秒后自动发送未成功消息
                        if (!isSend)
                            sendMessage(mt, sendMsg, 2000);
                    }


                    break;
                }
//                登录
                case LOGIN_SEND: {

                    String tel = SPUtilHelper.getPhone();
                    String password =SPUtilHelper.getPwd();
                    if (!"".equals(tel)&&!"".equals(password))
                    {
                        TcpNetHelper.login(tel,password);
                    }else
                    {
                        if (listener!=null)
                        {
                            nettyClientHandler.callListeners(TcpNetHelper.UNLOGIN,"未登录");
                        }
                    }

                    break;
                }
            }
            return true;
        }
    };


    private NettyClient() {
        init();
    }

    /**
     * 获得单例
     *
     * @return
     */
    public synchronized static NettyClient getInstance() {
        if (mInstance == null)
            mInstance = new NettyClient();
        return mInstance;
    }

    /**
     * 重连机制,每隔2s重新连接一次服务器
     */
    protected void doConnect() {
        Log.i("-->","连接的IP:"+host+"  端口号："+port);
//        if (channel != null && channel.isActive()) {
//            return;
//        }

        ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));

        future.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture futureListener) throws Exception {
                if (futureListener.isSuccess()) {
                    channel = futureListener.channel();

                    Log.i("-->", "Connect to server successfully!");
                    //连接成功 自动登录
                    if (isFirst)
                    {
                        mWorkHandler.sendEmptyMessage(LOGIN_SEND);
                    }else {
                        nettyClientHandler.callListeners(TcpNetHelper.CONNECTSUCC,"连接成功");
                    }


                } else {
                    Log.i("-->", "Failed to connect to server, try connect after 2s");
                    //重新连接
                    futureListener.channel().eventLoop().schedule(new Runnable() {
                        @Override
                        public void run() {
                            doConnect();
                        }
                    }, 2, TimeUnit.SECONDS);
                }
            }
        });
    }


    private void init() {
        workThread = new HandlerThread(NettyClient.class.getName());
        workThread.start();
        mWorkHandler = new Handler(workThread.getLooper(), mWorkHandlerCallback);
        nettyClientHandler = new NettyClientHandler();
        nettyClientHandler.setConnectStatusListener(new OnConnectStatusListener() {
            @Override
            public void onDisconnected() {
                //连接中断 重新连接
                sendReconnectMessage();
                isFirst=true;
            }

            @Override
            public void onOtherLogin() {
                //其他人登录

            }


            @Override
            public void onOtherHostAndPort(String hosts, int ports) {
                //更换host和port
                host=hosts;
                port=ports;
                sendReconnect();
            }
        });
        mWorkHandler.sendEmptyMessage(MESSAGE_INIT);
    }

    /**
     * 连接
     *
     * @param host ip地址
     * @param port 端口号
     */
    @Override
    public void connect(String host, int port) {
        this.host = host;
        this.port = port;
        mWorkHandler.sendEmptyMessage(MESSAGE_CONNECT);
    }

    //向外传输数据的接口
    private  OnDataReceiveListener listener;
    /**
     * 数据返回的监听
     *
     * @param listener
     */
    @Override
    public void addDataReceiveListener(OnDataReceiveListener listener) {
        if (nettyClientHandler != null)
        {
            this.listener=listener;
            nettyClientHandler.addDataReceiveListener(listener);
        }

    }

    /**
     *解除监听
     *
     * @param listener
     */
    public void delectDataReceiveListener(OnDataReceiveListener listener) {
        if (nettyClientHandler != null)
        {
            nettyClientHandler.delectDataReceiveListener(listener);
        }

    }

    /**
     * 重新连接
     */
    public void sendReconnectMessage() {
        mWorkHandler.sendEmptyMessageDelayed(MESSAGE_CONNECT, 100);
    }

    /**
     * 先断线在重新
     */
    public void sendReconnect() {
        channel=null;
        mWorkHandler.sendEmptyMessageDelayed(MESSAGE_CONNECT, 100);
    }
    /**
     * 发送消息
     *
     * @param mt
     * @param msg
     * @param delayed
     */
    @Override
    public void sendMessage(int mt, String msg, long delayed) {
//        if (TextUtils.isEmpty(msg))
//            return;
        Message message = new Message();
        Bundle bundle = new Bundle();
        message.what = MESSAGE_SEND;
        bundle.putString(ACTION_SEND_MSG, msg);
        bundle.putInt(ACTION_SEND_TYPE, mt);
        message.setData(bundle);
        mWorkHandler.sendMessageDelayed(message, delayed);
    }


    private int pos=0;


}

